/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/


#include "stdafx.h"
#include "S_Physics.h"

#include "S_键值序列容器.h"
#include "解算器/physics_解算器基类.h"

#include "物理/物理.h"

//#include <PxPhysicsAPI.h>
//#include <vehicle2/PxVehicleParams.h>
//#include <vehicle2/PxVehicleAPI.h>



#define PVD_HOST "127.0.0.1"

static S_键值序列容器<uint32, S_Object*> g_物理容器;


void f_init车轮参数(S_车轮参数& c) {
	c.m_悬挂刚度 = 20.0f;
	c.m_悬挂阻尼 = 2.0f;
	c.m_悬挂压缩 = 5.0f;

	c.m_轮胎摩擦 = 1000.0f;
	c.m_旋转影响 = 0.1f;
}



void f_phy_创建几何体数据(S_物理几何体* geom, E_物理几何体类型 几何体类型) {
	void* 销毁物体 = geom->m_Data;
	geom->m_Type = 几何体类型;

	
	switch (几何体类型) {
		case E_物理几何体类型::E_碰撞几何_方体: {
			geom->m_Data = calloc(1, sizeof(S_物理几何_方体));
			((S_物理几何_方体*)geom->m_Data)->大小 = { 1,1,1 };
			((S_物理几何_方体*)geom->m_Data)->m_Data = nullptr;
			break;
		}

		case E_物理几何体类型::E_碰撞几何_圆柱: {
			geom->m_Data = calloc(1, sizeof(S_物理几何_圆柱));
			((S_物理几何_圆柱*)geom->m_Data)->大小 = { 1,1,1 };
			((S_物理几何_圆柱*)geom->m_Data)->m_Data = nullptr;
			break;
		}

		case E_物理几何体类型::E_碰撞几何_球体: {
			geom->m_Data = calloc(1, sizeof(S_物理几何_球体));
			((S_物理几何_球体*)geom->m_Data)->大小 = 1;
			((S_物理几何_球体*)geom->m_Data)->m_Data = nullptr;
			break;
		}

		case E_物理几何体类型::E_碰撞几何_胶囊: {
			geom->m_Data = calloc(1, sizeof(S_物理几何_胶囊));
			((S_物理几何_胶囊*)geom->m_Data)->大小 = {1,1};
			((S_物理几何_胶囊*)geom->m_Data)->m_Data = nullptr;
			break;
		}

		case E_物理几何体类型::E_碰撞几何_凸壳: {
			return;
		}

		case E_物理几何体类型::E_碰撞几何_平面: {
			geom->m_Data = calloc(1, sizeof(S_物理几何_平面));
			((S_物理几何_平面*)geom->m_Data)->方向 = { 0, 1, 0 };
			((S_物理几何_平面*)geom->m_Data)->位置 = { 0, 0, 0 };
			((S_物理几何_平面*)geom->m_Data)->m_Data = nullptr;
			break;
		}

		case E_物理几何体类型::E_碰撞几何_网格: {
			geom->m_Data = calloc(1, sizeof(S_物理几何_网格));
			((S_物理几何_网格*)geom->m_Data)->顶点 = nullptr;
			((S_物理几何_网格*)geom->m_Data)->索引 = nullptr;
			((S_物理几何_网格*)geom->m_Data)->顶点数量 = 0;
			((S_物理几何_网格*)geom->m_Data)->索引数量 = 0;
			break;
		}

		case E_物理几何体类型::E_碰撞几何_地形: {
			break;
		}
	}

	if (销毁物体) {
		free(销毁物体);
	}
}



S_物理几何体* f_phy_创建几何体(E_物理几何体类型 几何体类型, E_物理引擎 物理引擎) {
	auto geom = new S_物理几何体(几何体类型);

	f_phy_创建几何体数据(geom, 几何体类型);

	return geom;
}

void f_phy_销毁几何体(S_物理几何体* geom) {
	if (geom->m_Data) {
		free(geom->m_Data);
	}
	delete geom;
}

void S_Physics::f_重置变换(bool 解算) {
	
}



//static physx::vehicle2::PxVehiclePhysXSimulationContext gVehicleSimulationContext;

/*
static std::map<std::string, S_PxScene> gGPU计算环境回收站;
static std::map<uint16_t, S_PxPhy> gDispatcher回收站;

physx::PxFoundation* S_Px物理引擎管理::gFoundation = nullptr;
physx::PxPhysics* S_Px物理引擎管理::gPhysics = nullptr;
physx::PxMaterial* S_Px物理引擎管理::gPxMaterial = nullptr;
physx::PxPBDMaterial* S_Px物理引擎管理::gPxPBDMaterial = nullptr;
physx::PxCookingParams* S_Px物理引擎管理::gPxParams = nullptr;
std::map<uint16_t, S_PxPhy> S_Px物理引擎管理::gDispatcher;
std::map<std::string, S_PxScene> S_Px物理引擎管理::g场景环境;



S_Px物理引擎管理::S_Px物理引擎管理() {
	
	if (!gFoundation) {
		static physx::PxDefaultErrorCallback gDefaultErrorCallback;
		static physx::PxDefaultAllocator gDefaultAllocatorCallback;
		static physx::PxTolerancesScale scale;

		gFoundation = PxCreateFoundation(PX_PHYSICS_VERSION, gDefaultAllocatorCallback,
										 gDefaultErrorCallback);
		if (!gFoundation) {
			std::cout << "创建物理环境失败\n";
			return;
		}

		auto gPvd = PxCreatePvd(*gFoundation);
		physx::PxPvdTransport* transport = physx::PxDefaultPvdSocketTransportCreate(PVD_HOST, 5425, 10);
		gPvd->connect(*transport,physx::PxPvdInstrumentationFlag::ePROFILE);
		gPhysics = PxCreatePhysics(PX_PHYSICS_VERSION, *gFoundation, scale, true, nullptr);

		gPxParams = new physx::PxCookingParams(scale);
		gPxParams->meshWeldTolerance = 0.001f;
		gPxParams->meshPreprocessParams = physx::PxMeshPreprocessingFlags(physx::PxMeshPreprocessingFlag::eWELD_VERTICES);
		gPxParams->buildTriangleAdjacencies = false;
		gPxParams->buildGPUData = true;


		gPxMaterial = gPhysics->createMaterial(0.5f, 0.5f, 0.3f);

		gPxPBDMaterial = gPhysics->createPBDMaterial(0.05f, 0.05f, 0.f, 0.001f, 0.5f, 0.005f, 0.01f, 0.f, 0.f);
		gPxPBDMaterial->setViscosity(0.001f);
		gPxPBDMaterial->setSurfaceTension(0.00704f);
		gPxPBDMaterial->setCohesion(0.0704f);
		gPxPBDMaterial->setVorticityConfinement(10.f);

		physx::vehicle2::PxInitVehicleExtension(*gFoundation);

	}
}

S_Px物理引擎管理::~S_Px物理引擎管理() {
	if (gPhysics) {
		if (g场景环境.size()) {
			for (auto& e : g场景环境) {
				e.second.m_Scene->release();
			}
		}
		if (gGPU计算环境回收站.size()) {
			for (auto& e : gGPU计算环境回收站) {
				e.second.m_Scene->release();
			}
		}
		

		gPhysics->release();
		gPhysics = nullptr;

		g场景环境.clear();
		gGPU计算环境回收站.clear();
	}
}

physx::PxPhysics* S_Px物理引擎管理::f_getPhy() {
	if (!gPhysics) S_Px物理引擎管理::S_Px物理引擎管理();
	return gPhysics;
}

physx::PxCookingParams& S_Px物理引擎管理::f_getParams() {
	return *gPxParams;
}

S_PxPhy S_Px物理引擎管理::f_创建环境(uint16 线程数) {
	S_PxPhy physics{};
	physics.m_CpuDispatcher = physx::PxDefaultCpuDispatcherCreate(线程数);
	return physics;
}

int16_t S_Px物理引擎管理::f_分配新环境() {
	static int16_t id = 0;
	int16_t key;

	S_PxPhy physics{};
	if (gDispatcher回收站.empty()) {
		physics = f_创建环境(8);
		++id;
		key = id;
	}
	else {
		auto it = gDispatcher回收站.begin();
		physics = (*it).second;
		key = (*it).first;
		gDispatcher回收站.erase(key);
	}
	gDispatcher[key] = physics;

	return key;
}

void S_Px物理引擎管理::f_重置环境(const int16 key, const uint16 线程数) {
	if (gDispatcher.find(key) != gDispatcher.end()) {
		gDispatcher[key].m_CpuDispatcher->release();
		gDispatcher[key] = f_创建环境(线程数);
	}
	else {
		if (key) {
			auto phy = f_创建环境(线程数);
			gDispatcher[key] = phy;
		}
	}
}

void S_Px物理引擎管理::f_删除环境(const int16 key) {
	if (gDispatcher.find(key) != gDispatcher.end()) {
		gDispatcher回收站[key] = gDispatcher[key];
		gDispatcher.erase(key);
	}
}



void S_Px物理引擎管理::f_创建GPU场景环境(S_PxScene& scene) {
	if (PxGetSuggestedCudaDeviceOrdinal(gFoundation->getErrorCallback()) >= 0) {
		// initialize CUDA
		physx::PxCudaContextManagerDesc cudaContextManagerDesc;
		scene.m_GPUCext = PxCreateCudaContextManager(*gFoundation, cudaContextManagerDesc, PxGetProfilerCallback());
		if (scene.m_GPUCext && !scene.m_GPUCext->contextIsValid()) {
			scene.m_GPUCext->release();
			scene.m_GPUCext = nullptr;
		}
	}
	if (scene.m_GPUCext == nullptr) {
		PxGetFoundation().error(physx::PxErrorCode::eINVALID_OPERATION, PX_FL, "Failed to initialize CUDA!\n");
	}
}

void S_Px物理引擎管理::f_释放场景环境(int16 keyName) {
	auto key = std::to_string(keyName);
	if (g场景环境.find(key) != g场景环境.end()) {
		auto& ctx = g场景环境[key];
		if (ctx.m_Scene) {
			ctx.m_Scene->release();
			ctx.m_Scene = nullptr;
		}

		gGPU计算环境回收站[key] = g场景环境[key];
		g场景环境.erase(key);
	}
}

int16 S_Px物理引擎管理::f_分配场景环境() {
	static int16_t id = 0;

	int16 custom1;
	S_PxScene scene{};
	if (gGPU计算环境回收站.empty()) {
		f_创建GPU场景环境(scene);
		++id;
		custom1 = id;
	}
	else {
		auto it = gGPU计算环境回收站.begin();
		scene = (*it).second;
		custom1 = std::stoi((*it).first);
		gGPU计算环境回收站.erase((*it).first);
	}

	g场景环境[std::to_string(id)] = scene;
	return custom1;
}

S_PxScene* S_Px物理引擎管理::f_创建场景对象(const std::string& 场景, int32 设备ID, const vec3& 重力) {
	if (S_Px物理引擎管理::g场景环境.find(场景) == S_Px物理引擎管理::g场景环境.end()) {
		S_PxScene scene{};
		S_Px物理引擎管理::f_创建GPU场景环境(scene);
		S_Px物理引擎管理::g场景环境[场景] = scene;
	}
	auto& ctx = S_Px物理引擎管理::g场景环境[场景];

	if (ctx.m_Scene) {
		f_phy_重置车辆模拟(ctx.m_Scene);

		ctx.m_Scene->release();
		ctx.m_粒子缓存.clear();
		ctx.m_Scene = nullptr;
	}
	auto it = gDispatcher.find(设备ID);

	if (it != gDispatcher.end()) {
		physx::PxSceneDesc sceneDesc(S_Px物理引擎管理::gPhysics->getTolerancesScale());

		auto& phy = (*it).second;

		sceneDesc.gravity = { 重力.x, 重力.y, 重力.z };
		sceneDesc.cpuDispatcher = phy.m_CpuDispatcher;
		sceneDesc.filterShader = physx::PxDefaultSimulationFilterShader;
		sceneDesc.cudaContextManager = ctx.m_GPUCext;
		sceneDesc.staticStructure = physx::PxPruningStructureType::eDYNAMIC_AABB_TREE;
		sceneDesc.flags |= physx::PxSceneFlag::eENABLE_PCM;
		sceneDesc.flags |= physx::PxSceneFlag::eENABLE_GPU_DYNAMICS;
		sceneDesc.broadPhaseType = physx::PxBroadPhaseType::eGPU;
		sceneDesc.solverType = physx::PxSolverType::eTGS;
		sceneDesc.gpuDynamicsConfig.collisionStackSize = 185793888;

		ctx.m_Scene = S_Px物理引擎管理::gPhysics->createScene(sceneDesc);


		//gVehicleSimulationContext.gravity = sceneDesc.gravity;
		//gVehicleSimulationContext.physxScene = ctx.m_Scene;
		//gVehicleSimulationContext.physxActorUpdateMode = physx::vehicle2::PxVehiclePhysXActorUpdateMode::eAPPLY_ACCELERATION;

		f_phy_重置车辆模拟环境(ctx.m_Scene);


		physx::PxPvdSceneClient* pvdClient = ctx.m_Scene->getScenePvdClient();
		if (pvdClient) {
			pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS, true);
			pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_CONTACTS, true);
			pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES, true);
		}

		
		return &ctx;
	}
	return nullptr;
}
*/



S_物体* f_phy_get粒子物体对象(S_Object* 物理体) {
	return (S_物体*)(((S_物理体*)物理体)->m_Data);
}

